#include "server_pico.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>




#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <ev.h>


// TODO:1 alpn
//TODO：证书 第一个参数
//TODO: 参数设置
//TODO: local_addr 哪里传入的

//TODO:没有index 跟据index 确定在包是哪个链路的

#define SERVER_PORT 6015
#define CLIENT_IP "192.168.43.230" // 客户端 IP，替换为实际值
#define CLIENT_IF_NAME "enp2s0"
#define CLIENT_PORT 6014
#define BUFFER_SIZE 1536
// #define CA_CERT "../cert-bak/ca-cert.pem"
// #define SERVER_KEY "../cert-bak/server-key.pem"

#define CA_CERT "../cert/cert.pem"
#define SERVER_KEY "../cert/key.pem"

struct ServerContext {
    int sockfd;
    struct sockaddr_in local_addr;
    struct sockaddr_in from_addr;
    // struct sockaddr_in client_addr;
    ev_io io_watcher;
    ev_timer timer_watcher;
    picoquic_quic_t* quic = NULL;
    picoquic_cnx_t* cnx = NULL;
    uint64_t stream_id = 1;//默认值为1 服务端的双向流
};
ServerContext ctx;


#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>

static void print_ip_port(struct sockaddr_storage *peer_addr) 
{
    char ip_str[INET6_ADDRSTRLEN]; // 足够存储 IPv4 或 IPv6 地址
    int port;

    if (peer_addr->ss_family == AF_INET) {
        // IPv4
        struct sockaddr_in *addr = (struct sockaddr_in *)peer_addr;
        inet_ntop(AF_INET, &(addr->sin_addr), ip_str, sizeof(ip_str));
        port = ntohs(addr->sin_port);
        printf("-----IPv4\n");
    } else if (peer_addr->ss_family == AF_INET6) {
        // IPv6
        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)peer_addr;
        inet_ntop(AF_INET6, &(addr->sin6_addr), ip_str, sizeof(ip_str));
        port = ntohs(addr->sin6_port);
        printf("-----IPv6\n");
    } else {
        strcpy(ip_str, "Unknown");
        printf("-----IPv6----------IPv4\n");
        port = 0;
    }

    printf("IP: %s, Port: %d\n", ip_str, port);
}

static int get_recv_buffer(void* recv_buffer, int bytes_recv, struct sockaddr* from_addr_)
{
    uint64_t current_time = picoquic_current_time();
    //TODO:没有index
    int ret = picoquic_incoming_packet(ctx.quic, (uint8_t *)recv_buffer, (size_t)bytes_recv, (struct sockaddr *)(from_addr_), (struct sockaddr *)&(ctx.local_addr), 0, 0, current_time);
    if(ret != 0)
    {
        printf("picoquic_incoming_packet error!\n");
        return 1;
    }
    /*
    printf("recv loacl:\n");
    print_ip_port((sockaddr_storage *)&(ctx.local_addr));
    printf("recv peer:\n");
    print_ip_port((sockaddr_storage *)(from_addr_));
    */

    return 0;
}

static int get_send_buffer(void* send_buffer_, size_t& send_length_, struct sockaddr_storage* peer_addr)
{
    int if_index = -2;
    int sock_ret = 0;
    size_t send_length = 0;
    uint8_t send_buffer[1536];
    picoquic_connection_id_t log_cid;
    picoquic_cnx_t *last_cnx = nullptr;
    // struct sockaddr_storage peer_addr;
    struct sockaddr_storage local_addr;
    size_t *send_msg_ptr = nullptr;

    uint64_t current_time = picoquic_current_time();
    int ret = picoquic_prepare_next_packet_ex(ctx.quic, current_time, (uint8_t *)send_buffer_, 1536,
                                          &send_length, peer_addr, &local_addr, &if_index, &log_cid, &last_cnx, send_msg_ptr);
    if(ret != 0)
    {
        printf("picoquic_prepare_next_packet_ex error\n");
        return 1;
    }
        
    //TODO: local_addr 哪里传入的
    send_length_ = send_length;
    if(send_length_ != 0)
    {
        /*
        printf("sendto loacl:\n");
        print_ip_port(&local_addr);
        printf("sendto peer:\n");
        print_ip_port(peer_addr);
        */
    }

    return 0;
}

// 接收数据的回调函数
static void recv_cb(EV_P_ ev_io *w, int revents) {
    // ServerContext *ctx_ = static_cast<ServerContext*>(w->data);
    char buffer[BUFFER_SIZE];

    socklen_t addr_len = sizeof(ctx.from_addr);

    ssize_t len = recvfrom(ctx.sockfd, buffer, BUFFER_SIZE, 0,
                           (struct sockaddr*)&ctx.from_addr, &addr_len);

    if (len < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) return; // 暂无数据
        perror("recvfrom failed");
        ev_break(EV_A_ EVBREAK_ALL);//TODO:
        return;
    }
    print_ip_port((sockaddr_storage *)&ctx.from_addr);
    //--
    int ret = get_recv_buffer(buffer, len, (sockaddr *)&ctx.from_addr);
    if(ret != 0)
    {
        printf("get_recv_buffer error\n");
    }

    //++
    // buffer[len] = '\0';
    std::cout << "Received from client length: " << len << std::endl;
}

// 发送数据的回调函数（定时器触发）
static void send_cb(EV_P_ ev_timer *w, int revents) 
{
    ServerContext *ctx = static_cast<ServerContext*>(w->data);
    if(ctx->cnx != NULL)
    {
        //picoquic_add_to_stream(ctx->cnx, ctx->stream_id, (const uint8_t*)"---from server", 100, 0);//0不是fin 100字节
    }

    std::string message = "Hello from server at " + std::to_string(time(nullptr));
    ssize_t sent = 0;
    //--
    uint8_t send_buffer_[1536];
    size_t send_length_ = 0;
    struct sockaddr_storage peer_addr;
    int ret = get_send_buffer(send_buffer_, send_length_, &peer_addr);
    if(ret != 0)
    {
        printf("get_send_buffer error ret:%d send_length_:%d \n", ret , send_length_);
        return;
        // exit(1);
    }
    if(send_length_ == 0) return;
    sent = sendto(ctx->sockfd, send_buffer_, send_length_, 0,
                            (struct sockaddr*)&peer_addr, sizeof(peer_addr));
    //++
    // ssize_t sent = sendto(ctx->sockfd, message.c_str(), message.size(), 0,
    //                       (struct sockaddr*)&ctx->client_addr, sizeof(ctx->client_addr));
    if (sent < 0) {
        perror("sendto failed");
        ev_break(EV_A_ EVBREAK_ALL);
        return;
    }
    std::cout << "Sent to client length: " << sent << "   all_len:" << send_length_ << std::endl;
}
static int open_socket()
{
    // 创建 UDP socket
    ctx.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (ctx.sockfd < 0)
    {
        perror("socket creation failed");
        return 1;
    }

    // 设置 socket 为非阻塞
    int flags = fcntl(ctx.sockfd, F_GETFL, 0);
    fcntl(ctx.sockfd, F_SETFL, flags | O_NONBLOCK);

    // 绑定到本地 enp2s0 网卡
    // struct sockaddr_in local_addr;
    memset(&ctx.local_addr, 0, sizeof(ctx.local_addr));
    ctx.local_addr.sin_family = AF_INET;
    // ctx.local_addr.sin_addr.s_addr = INADDR_ANY; // 绑定任意 IP
    ctx.local_addr.sin_addr.s_addr = inet_addr(CLIENT_IP);
    ctx.local_addr.sin_port = htons(SERVER_PORT);

    struct ifreq ifr;
    strncpy(ifr.ifr_name, CLIENT_IF_NAME, IFNAMSIZ - 1);
    if (setsockopt(ctx.sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0)
    {
        perror("SO_BINDTODEVICE failed");
        close(ctx.sockfd);
        return 1;
    }

    if (bind(ctx.sockfd, (struct sockaddr *)&(ctx.local_addr), sizeof(ctx.local_addr)) < 0)
    {
        perror("bind failed");
        close(ctx.sockfd);
        return 1;
    }

    // 设置客户端地址
    // struct sockaddr_in client_addr;
    // memset(&(ctx.client_addr), 0, sizeof(ctx.client_addr));
    // ctx.client_addr.sin_family = AF_INET;
    // ctx.client_addr.sin_port = htons(CLIENT_PORT);
    // if (inet_pton(AF_INET, CLIENT_IP, &(ctx.client_addr.sin_addr)) <= 0)
    // {
    //     perror("inet_pton failed");
    //     close(ctx.sockfd);
    //     return 1;
    // }

    return 0;
}

int sample_server_callback(picoquic_cnx_t *cnx,
                           uint64_t stream_id, uint8_t *bytes, size_t length,
                           picoquic_call_back_event_t fin_or_event, void *callback_ctx, void *v_stream_ctx)
{
    int ret = 0;
    switch (fin_or_event)
    {
    case picoquic_callback_stream_data:
    case picoquic_callback_stream_fin:
    {
        // printf("--picoquic_callback_stream_data--\n");
        // if (picoquic_set_app_stream_ctx(cnx, stream_id, NULL) != 0) {
        //     /* Internal error */
        //     (void) picoquic_reset_stream(cnx, stream_id, PICOQUIC_SAMPLE_INTERNAL_ERROR);
        //     return(-1);
        // }
        // int ret = picoquic_mark_active_stream(cnx, stream_id, 1, NULL);
        // if(ret != 0)
        //  {
        //     printf("picoquic_mark_active_stream error!\n");
        //  }
        printf("--------receive:%s  receive id:%d\n", (char*)bytes, stream_id);
        //如果想使用客户端的双向流id，把会这里的stream_id填入picoquic_add_to_stream()就可以使用了

        // picoquic_close(cnx, 0); 如果什么都处理完了，则发送close帧，触发对方picoquic_callback_close事件

        break;
    }
    case picoquic_callback_stop_sending: /* Should not happen, treated as reset */
    case picoquic_callback_stream_reset: /* Server reset stream #x */
    {
        printf("--picoquic_callback_stream_reset--\n");
        picoquic_reset_stream(cnx, stream_id, 0);
    }
        break;
    case picoquic_callback_stateless_reset:
    {
        printf("--picoquic_callback_stateless_reset--\n");
    }
    case picoquic_callback_close:             /* Received connection close */
    {
        printf("--picoquic_callback_close--\n");
    }
    case picoquic_callback_application_close: /* Received application close */
    {
        printf("--picoquic_callback_application_close--\n");
        picoquic_set_callback(cnx, nullptr, nullptr);
    }
        break;

    case picoquic_callback_version_negotiation:
                /* The client did not get the right version.
             * TODO: some form of negotiation?
             */
            fprintf(stdout, "Received a version negotiation request:");
            for (size_t byte_index = 0; byte_index + 4 <= length; byte_index += 4) {
                uint32_t vn = 0;
                for (int i = 0; i < 4; i++) {
                    vn <<= 8;
                    vn += bytes[byte_index + i];
                }
                fprintf(stdout, "%s%08x", (byte_index == 0) ? " " : ", ", vn);
            }
            fprintf(stdout, "\n");
            break;
    case picoquic_callback_stream_gap:
        break;

    case picoquic_callback_prepare_to_send:
    {
        printf("--picoquic_callback_prepare_to_send--\n");
        // 先获取可发送数据的长度，根据长度和fin填充quic协议得到可发数据的缓存，在获取发送的数据
    }
        break;

    case picoquic_callback_almost_ready:
    {
        printf("--picoquic_callback_almost_ready--\n");
        break;
    }

    case picoquic_callback_ready:
    {
        printf("--picoquic_callback_ready--\n");
        ctx.cnx = cnx;
        ctx.stream_id = picoquic_get_next_local_stream_id(ctx.cnx, 0); // 0为双向流 因为上下文是服务端的，因此会自动获取服务端的双向流
        /*
        0：客户端模式，双向流。
        1：服务器模式，双向流。
        2：客户端模式，单向流。
        3：服务器模式，单向流。
        */
        break;
    }

    case picoquic_callback_request_alpn_list:
    {
        printf("--picoquic_callback_request_alpn_list--\n");
        // TODO:1
        {
            // if (picoquic_add_proposed_alpn((void *)bytes, (const char *)c_quic->opt.alpn_list[i].base))
            // {
            // 	break;
            // }
        }
        break;
    }

    case picoquic_callback_set_alpn:
    {
        printf("--picoquic_callback_set_alpn--\n");
        break;
    }
    default:
        /* unexpected -- just ignore. */
        break;
    }

    return 0;
}




static int init_picoquic()
{
    uint64_t current_time = picoquic_current_time();
    //如果未开启tls，可以忽略这两个，填""
    std::string cert_file = CA_CERT; // "../cert/ca-cert.pem" pem公钥，通常包含私钥 .crt/.cer通常只包含公钥
    std::string key_file = SERVER_KEY; //"../cert/server-key.pem" //私钥

    // std::string cert_file = ""; // "../cert/ca-cert.pem" pem公钥，通常包含私钥 .crt/.cer通常只包含公钥
    // std::string key_file = ""; //"../cert/server-key.pem" //私钥
    //TODO：证书 第一个参数
    ctx.quic = picoquic_create(8, cert_file.c_str(), key_file.c_str(), NULL, PICOQUIC_SAMPLE_ALPN,
                           sample_server_callback, &ctx/*自定义结构体*/, NULL, NULL, NULL, current_time, NULL, NULL, NULL, 0);

    if (ctx.quic == NULL)
    {
        fprintf(stderr, "Could not create server context\n");
        return 1;
    }
    picoquic_set_cookie_mode(ctx.quic, 2);
    picoquic_set_default_congestion_algorithm(ctx.quic, picoquic_bbr_algorithm);
    char const *qlog_dir = PICOQUIC_SAMPLE_CLIENT_QLOG_DIR;
    picoquic_set_key_log_file_from_env(ctx.quic);
    picoquic_set_qlog(ctx.quic, qlog_dir);
    picoquic_set_log_level(ctx.quic, 1);



    //TODO: 参数设置

    picoquic_tp_t server_parameters = {0};
    picoquic_init_transport_parameters(&server_parameters, 0);
    server_parameters.enable_multipath = 1;
    picoquic_set_default_tp(ctx.quic, &server_parameters);




    return 0;
}

int main() {
   
    if(open_socket() != 0)
    {
        printf("error! open_socket!\n");
        exit(1);
    }
    init_picoquic();

    // 初始化 libev 事件循环
    struct ev_loop *loop = EV_DEFAULT;
    // 设置接收数据的 watcher
    ev_io_init(&ctx.io_watcher, recv_cb, ctx.sockfd, EV_READ);
    ctx.io_watcher.data = &ctx;
    ev_io_start(loop, &ctx.io_watcher);

    // 设置定时器，每 100ms 发送一次
    ev_timer_init(&ctx.timer_watcher, send_cb, 0.1, 0.1); // 初次延迟 100ms，之后每 100ms
    ctx.timer_watcher.data = &ctx;
    ev_timer_start(loop, &ctx.timer_watcher);

    std::cout << "Server started, bound to enp2s0, sending to " << CLIENT_IP << ":" << CLIENT_PORT << std::endl;

    // 运行事件循环
    ev_run(loop, 0);
    picoquic_free(ctx.quic);//ctx.cnx也会在这里被释放
    // 清理
    close(ctx.sockfd);
    return 0;
}
